<template>
  <div
    class="bc-form-panel"
    :style="`${props.border ? '' : 'border: none'};`"
    v-for="(item, index) in props.group ? formList : [{ list: formList }]"
    :key="index"
  >
    <div class="bc-form-title" v-if="item.name">
      <span>{{ item.name }}</span>
      <div :class="['bc-form-icon', { 'bc-form-icon-up': collapse[`item${index}`] === true }]">
        <el-icon
          :style="{ transform: `rotate(${collapse[`item${index}`] === true ? 180 : 0}deg)` }"
          @click="collapse[`item${index}`] = !collapse[`item${index}`]"
        >
          <ArrowDown />
        </el-icon>
      </div>
    </div>
    <div
      :class="['bc-form-content', { detail: props.mode === 'detail' }]"
      :style="{
        '--grid-cols': props.cols,
        padding: props.padding,
        ...(collapse[`item${index}`] === true ? {} : { height: 0, overflow: 'hidden', padding: 0 }),
      }"
    >
      <template v-for="(sub, subIndex) in item.list || []" :key="`${index}-${subIndex}`" >
        <slot v-if="sub.slotName" :name="sub.slotName"></slot>
        <div v-else :style="gridColumn(sub, subIndex)">
          <el-form-item  :label="sub.label" :prop="sub.prop" :rules="sub.rules">
          <bc-form-number
            v-if="sub.type === 'number'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-date
            v-else-if="['date', 'month', 'datetime', 'year'].includes(sub.type)"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-select
            v-else-if="sub.type === 'select'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            :form="formData"
            @change="handleChange($event, sub)"
          />
          <bc-form-search
            v-else-if="sub.type === 'search'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            :form="formData"
            @change="handleChange($event, sub)"
          />
          <bc-form-cascader
            v-else-if="sub.type === 'cascader'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            :form="formData"
            @change="handleChange($event, sub)"
          />
          <bc-form-modal
            v-else-if="sub.type === 'modal'"
            v-model="formData[sub.prop]"
            v-model:text="formData[sub.textProp || sub.prop]"
            :config="sub"
            :mode="props.mode"
            :form="formData"
            @change="handleChange($event, sub)"
          />
          <bc-form-radio
            v-else-if="sub.type === 'radio'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            :form="formData"
            @change="handleChange($event, sub)"
          />
          <bc-form-check-box
            v-else-if="sub.type === 'checkBox'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            :form="formData"
            @change="handleChange($event, sub)"
          />
          <bc-form-textarea
            v-else-if="sub.type === 'textarea'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-image
            v-else-if="sub.type === 'image'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-upload
            v-else-if="sub.type === 'upload'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-editor
            v-else-if="sub.type === 'editor'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-color
            v-else-if="sub.type === 'color'"
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
          <bc-form-input
            v-else
            v-model="formData[sub.prop]"
            :config="sub"
            :mode="props.mode"
            @change="handleChange($event, sub)"
          />
        </el-form-item>
        </div>
      </template>
    </div>
  </div>
</template>

<script setup>
// ============== 导入相关 ==============
import { cloneDeep } from 'lodash'
import { ArrowDown } from '@element-plus/icons-vue'
import BcFormInput from './components/BcFormInput.vue'
import BcFormNumber from './components/BcFormNumber.vue'
import BcFormSelect from './components/BcFormSelect.vue'
import BcFormDate from './components/BcFormDate.vue'
import BcFormRadio from './components/BcFormRadio.vue'
import BcFormCheckBox from './components/BcFormCheckBox.vue'
import BcFormSearch from './components/BcFormSearch.vue'
import BcFormTextarea from './components/BcFormTextarea.vue'
import BcFormImage from './components/BcFormImage.vue'
import BcFormUpload from './components/BcFormUpload.vue'
import BcFormModal from './components/BcFormModal.vue'
import BcFormEditor from './components/BcFormEditor.vue'
import BcFormCascader from './components/BcFormCascader.vue'
import BcFormColor from './components/BcFormColor.vue'
import { parseFlatObject } from './parseFlatObject'
import { reactive, watch } from 'vue'

// ============== Props 定义 ==============
const props = defineProps({
  /**
   * span占位，最大值为列数，最小值为1，默认为1
   * type number|date|month|datetime|year｜select|search｜list|radio|checkBox|textarea
   * prop form值
   * attrs 默认配置项
   * event 值改变事件
   * unit input|number 单位
   * onlyread 展示，false时不展示，'add'|'detail'|'edit'值单独展示，['add','detail']展示两个值
   * disabled 禁用，true时全禁用，'add'|'detail'|'edit'值单独禁用，['add','detail']禁用两个值
   * format 日期类组件 date|month|datetime|year 格式
   * linkage 选择器类 select|search｜list|radio|checkBox 是否联动
   * options 选择器类 select|search 选项，传入list或方法
   * textProp list组件展示文本字段，不传默认prop
   * columns list组件用，详见DataPanel组件
   * dataSource list组件用，详见DataPanel组件
   * rowKey list组件，绑定绑定用key
   * textKey list组件，绑定绑定用textkey
   * limit 文件组件最大值
   * rules 数组，表达校验规则
   */
  fields: {
    type: Array,
    default: () => [],
  },
  // 列数
  cols: {
    type: Number,
    default: 3,
  },
  mode: {
    // 'edit' | 'detail' | 'add'
    type: String,
    default: 'detail',
  },
  // 是否分组
  group: {
    type: Boolean,
    default: false,
  },
  // 是否展示边框
  border: {
    type: Boolean,
    default: true,
  },
  // 间距
  padding: {
    type: [Number, String],
    default: '16px',
  },
})
const emits = defineEmits(['change'])

const collapse = reactive({ item0: true, item1: true, item2: true, item3: true, item4: true, item5: true })

const formData = ref({})
const set = (info) => {
  formData.value = cloneDeep({ ...info })
}
// 处理配置项
const filterFields = (mode, arr) => {
  return arr
    .filter((item) => {
      if (typeof item.onlyread === 'string') {
        return mode === item.onlyread
      } else if (Array.isArray(item.onlyread)) {
        return item.onlyread.includes(mode)
      } else if (item.onlyread === false) {
        return false
      } else {
        return true
      }
    })
    .map((item) => {
      if (item?.disabled) {
        if (typeof item.disabled === 'string') {
          item['disabled'] = mode === item.disabled
        } else if (Array.isArray(item.disabled)) {
          item['disabled'] = item.disabled.includes(mode)
        } else {
          item['disabled'] = item.disabled
        }
        return item
      } else {
        return item
      }
    })
}
const formList = computed(() => {
  const { mode, fields, group } = props
  if (group) {
    return fields.map((item) => {
      return {
        name: item.name,
        list: filterFields(mode, cloneDeep(item.list)),
      }
    })
  } else {
    return filterFields(mode, cloneDeep(fields))
  }
})

// 布局列占比
const gridColumn = (col, index) => {
  if (col.span) {
    return {
      'grid-column': `span ${col.span > props.cols ? props.cols : col.span}`,
    }
  } else {
    return null
  }
}

const handleChange = async (value, item) => {
  const info = await item.event(value, formData.value)
  formData.value = { ...formData.value, ...info }
}

const ruleFormRef = ref()
const submit = () => {
  return new Promise((resolve, reject) => {
    ruleFormRef.value.validate((valid, fields) => {
      if (valid) {
        resolve(parseFlatObject(formData.value))
      } else {
        reject('请填写必填项')
      }
    })
  })
}
const reset = () => {
  formData.value = cloneDeep({})
}
watch(
  () => formData,
  (newVal, oldVal) => {
    emits('change', newVal, oldVal)
  },
  { deep: true }
)

defineExpose({
  set,
  submit,
  reset,
})
</script>

<style lang="scss" scoped>
.bc-form-panel {
  width: 100%;
  border-radius: 4px;
  border: 1px solid #e4e7ed;
  background-color: #fff;
  .bc-form-title {
    border-bottom: 1px solid #dfe0e1;
    padding: 12px 16px;
    display: flex;
    align-items: center;
    line-height: 22px;
    &::before {
      content: '';
      display: inline-block;
      width: 4px;
      height: 16px;
      border-radius: 10px;
      margin-right: 8px;
      background-color: var(--el-color-primary);
    }
    .bc-form-icon {
      flex: 1;
      text-align: right;
      padding-top: 4px;
    }
    .el-icon {
      cursor: pointer;
      transition: transform 0.5s ease;
    }
  }
  .bc-form-content {
    width: 100%;
    display: grid;
    gap: 0 12px;
    padding: 12px 16px;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
  }
  .detail {
    :deep(.el-form-item__label) {
      color: #727579;
    }
  }
}
.bc-form-panel + .bc-form-panel {
  margin-top: 12px;
}
</style>
